package com.bbva.kyfb.kyfbofi.objects;

import java.text.DecimalFormat;

import org.apache.commons.lang.StringUtils;

import com.bbva.jee.arq.spring.core.log.I18nLog;
import com.bbva.jee.arq.spring.core.log.I18nLogFactory;

/**
 * The Class Cuentas.
 *
 * @author: Marian Rivero Rosas
 */
public class Cuentas {

	/** Log de la clase Cuentas */
	private static final I18nLog LOG = I18nLogFactory.getLogI18n(Cuentas.class);

	private static final int[] ARR_BANCO = new int[]{4,8,5,10};

	private static final int[] ARR_OFICINA = new int[]{9,7,3,6};

	private static final int[] ARR_CUENTA = new int[]{1,2,4,8,5,10,9,7,3,6};

	private static final DecimalFormat FMT_2CEROS = new DecimalFormat("00");

	private static final int[] FCTR_MULT = new int[]{1,3,9,7,1,3,9,7,1,3,9,7};

	/**
	 * Inserte aquí la descripción del método. Fecha de creación: (31/05/2000
	 * 13:03:53)
	 *
	 * @param banco the banco
	 * @param oficina java.lang.String
	 * @param contrapartida java.lang.String
	 * @param folio java.lang.String
	 * @return java.lang.String
	 */
	public String bbvccc(final String banco, final String oficina, final String contrapartida, final String folio) {

		final StringBuilder cuenta = new StringBuilder();

		int digito = 0;

		try {

			final String folio6 = folio.substring(folio.length()-6);

			final StringBuilder campo1 = new StringBuilder(oficina).append(contrapartida.substring(contrapartida.length()-2)).append(folio6);

			digito = sumPlus(campo1.toString(),FCTR_MULT) % 10;

			// Realizamos los calculos para comprobar que el primer
			// dígito de Control sea correcto.
			int primerDigito = sumPlus(banco,ARR_BANCO) + sumPlus(oficina,ARR_OFICINA);
			// Realizamos el modulo 11 de primerDigito
			primerDigito = mod11(primerDigito);

			// Realizamos los cálculos para el segundo dígito de control

			final String contrapartida3 = contrapartida.substring(contrapartida.length()-3);

			cuenta.append(contrapartida3).append(folio6).append(digito);

			int segundoDigito = sumPlus(cuenta.toString(),ARR_CUENTA);

			segundoDigito = mod11(segundoDigito);

			digito = primerDigito*10+segundoDigito;

		} catch (final Exception ex) {
			LOG.error(ex, "bbvccc", banco, oficina, contrapartida, folio);
		}

		// Devolvemos el resultado
		return StringUtils.join(new Object[]{banco,oficina,digito,cuenta});

	}

	/**
	 * Trocea la cuanta en los pares de rangos especificados, si el ultimo es negativo devuelve el tamaño de la cuenta menos este.
	 * @param cuenta
	 * @param tks
	 * @return
	 */
	public String iban(final String cuenta, final int... tks){
		if (tks[7]<0){
			tks[7] = cuenta.length()+tks[7];
		}
		return iban(cuenta.substring(tks[0],tks[1]),cuenta.substring(tks[2],tks[3]),cuenta.substring(tks[4],tks[5]),cuenta.substring(tks[6],tks[7]));
	}

	/**
	 * Método que devuelve la cta. en formato IBAN a partir del formato banco,
	 * oficina, contrapartida y folio.. Este método solo funciona con cuentas
	 * españolas. Fecha de creación: (28/09/2000 11:43:47)
	 *
	 * @param banco the banco
	 * @param oficina the oficina
	 * @param contrapartida the contrapartida
	 * @param folio the folio
	 * @return java.lang.String
	 */
	public String iban(final String banco, final String oficina, final String contrapartida, final String folio) {

		// Calculamos primero la cta. en formato ccc.
		final String ccc = bbvccc(toIntLZero(banco, 4), toIntLZero(oficina, 4), toIntLZero(contrapartida, 3), toLngLZero(folio, 6));

		// Concatenamos al ccc 14, que es la conversión numerica de la "E" para
		// el calculo despues 28, que es la conversión numerica de la "E" para
		// el calculo y por último 00
		final StringBuilder aux = new StringBuilder(ccc).append("142800");

		// Quitamos los ceros que pudiera tener por delante (como mucho puede
		// tiene 3 ceros).

		for(int idx=0;idx<4;idx++){
			if (aux.charAt(idx)!='0'){
				aux.delete(0, idx);
				break;
			}
		}

		// Calculamos el modulo de 97 partiendo el número en numeros de 9
		// cifras.
		while (aux.length() > 9) {

			// Realizamos el calculo del modulo 97 del número.
			final int numero = Integer.parseInt(aux.substring(0, 9)) % 97;
			aux.delete(0,9);

			if (numero != 0) {
				// Si el módulo es distinto de 0 lo concateno.
				aux.insert(0, numero);
			}

		}

		final int check = 98 - Integer.parseInt(aux.toString()) % 97;

		return new StringBuilder("ES").append(FMT_2CEROS.format(check)).append(ccc).toString();
	}

	private static int sumPlus(final String str, final int... mlt) {
		int resp = 0;
		for(int i = 0;i<mlt.length;i++) {
			resp+=strPosToNum(str,i)*mlt[i];
		}
		return resp;
	}

	private static int strPosToNum(final String str, final int pos) {
		return str.charAt(pos)-'0';
	}

	/**
	 * Modulo 11 del numero
	 * @param num
	 * @return
	 */
	private static int mod11(final int num){
		int res = 11 - num % 11;

		if (res == 10) {
			res = 1;
		} else if (res == 11) {
			res = 0;
		}

		return res;
	}

	/**
	 * Comprueba que es un numero y lo devuelve como string con el numero de ceros especificado a la izquierda.
	 * Maximo tamanio int
	 * @param num
	 * @param numCeros
	 * @return
	 */
	private static final String toIntLZero(final String num,final int numCeros){
		return StringUtils.leftPad(String.valueOf(Integer.valueOf(num)),numCeros, '0');
	}

	/**
	 * Comprueba que es un numero y lo devuelve como string con el numero de ceros especificado a la izquierda.
	 * Maximo tamanio long
	 * @param num
	 * @param numCeros
	 * @return
	 */
	private static final String toLngLZero(final String num,final int numCeros){
		return StringUtils.leftPad(String.valueOf(Long.valueOf(num)),numCeros);
	}

	/*
	 * Insert the method's description here. Creation date: (07/06/2000 12:31:06
	 * PM)
	 *
	 * @param banco the banco
	 * @param oficina the oficina
	 * @param dgtCtrl the dc
	 * @param cuenta the cuenta
	 * @return boolean
	 *
	public boolean validarDC(final String banco, final String oficina, final String dgtCtrl, final String cuenta) {

		boolean dcValidado = false;

		// Realizamos los calculos para comprobar que el primer
		// dígito de Control sea correcto.
		int numero = sumPlus(banco,ARR_BANCO) + sumPlus(oficina,ARR_OFICINA);

		// Realizamos el modulo 11 de numero
		numero = mod11(numero);

		// Comprobamos que el Primer dígito de Control sea correcto.
		dcValidado = numero == Integer.parseInt(dgtCtrl.substring(0, 1));

		if (dcValidado) {
			// Si el Primer Dígito de Control es correcto.
			// Realizamos los cálculos para el segundo dígito de control.
			numero = sumPlus(cuenta,ARR_CUENTA);

			numero = mod11(numero);

			// Comprobamos que el segundo dígito de Control sea correcto.
			dcValidado = numero == Integer.parseInt(dgtCtrl.substring(1, 2));
		}

		// Devolvemos el resultado
		return dcValidado;
	}

	/*
	 * Inserte aquí la descripción del método. Fecha de creación: (22/03/2001
	 * 10:50:27)
	 *
	 * @param banco the banco
	 * @param oficina the oficina
	 * @param cuenta the cuenta
	 * @return java.lang.String
	 *
	public static String crearDigitoControl(final String banco, final String oficina, final String cuenta) {

		int primerDigito = sumPlus(banco,ARR_BANCO) + sumPlus(oficina,ARR_OFICINA);

		// Realizamos el modulo 11 de primerDigito
		primerDigito = mod11(primerDigito);

		int segundoDigito = sumPlus(cuenta,ARR_CUENTA);
		// Realizamos el modulo 11 de segundoDigito
		segundoDigito = mod11(segundoDigito);

		return String.valueOf(primerDigito*10+segundoDigito);
	}

	/*
	 * Inserte aquí la descripción del método. Fecha de creación: (22/03/2001
	 * 10:51:51)
	 *
	 * @param ccc the ccc
	 * @return java.lang.String
	 *
	public static String formatoCCC(final String ccc) {
		final String banco = ccc.substring(0, 4);
		final String oficina = ccc.substring(5, 9);
		final String contrapartida = ccc.substring(10, 13);
		final String folio = ccc.substring(14, 20);
		final StringBuilder resp = new StringBuilder(banco).append("-").append(oficina).append("-");

		try {
			final String digInterno = crearDigitoInterno(oficina, contrapartida, folio);
			final String cuenta = contrapartida + folio + digInterno;
			resp.append(crearDigitoControl(banco, oficina, cuenta));
			resp.append("-").append(cuenta);
		} catch (final Exception e) {
			LOG.error(e, "formatoCCC", ccc);
		}

		return resp.toString();
	}

	private static int extPos1(final int num){

		int fctr = 1;
		while(fctr<1234){
			fctr*=10;
		}
		fctr/=100;

		return (num-num%fctr)/fctr%10;
	}

	private static int extDigUn(final String str, final int... mlt) {
		int resp = 0;
		int aux;
		for(final int num:mlt) {
			aux = strPosToNum(str,1) * num;
			resp += aux > 9?extPos1(aux):aux;
		}
		return resp;
	}*/
}
